﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<assert.h>
#include<string.h>
//atoi函数就是将一个字符串转化为一个整型
//例如：
//头文件：<stdlib.h>
#include<stdlib.h>
/*
int main()
{
	char arr[] = "12346453";//放入字符拆串
	int m = atoi(arr);//转化为整型
	printf("%d\n", m);//用整形
	return 0;
}
*/

//分情况：
//1，可以有负号

//2，如果字符串中有其它字符时又会发生什么
// 1234a5678
// 它会将非数字字符的后面包括它本身的部分去掉 
//1234

//模拟实现
//普通（全为整型的情况）
//相当于：用指针遍历整个字符串，结果是从第一个字符开始，将（第一位x10，加上此位的值）== n，作为下一次的前一位，再去（前一位x10，加上此位的值）
/*
int my_atoi(char* arr)//用字符型的指针来接
{
    int n = 0;
    while (*arr != '\0')
    {
        n = n * 10 + *arr;
        arr++;//向后移动
    }
}
*/
//有时避免不了传入空指针
//所以要在遍历的时候，用assert断言
/*
二、模拟实现atoi
我们前面实验了几种特殊的情况，那么我们就可以针对上面的几点特殊情况一一解决

1.普通情况
既然要将一个字符串转化成一个整型，我们就想到了，我们从字符串的开头，让前面的字符相加在与10相乘加上后面的字符值，一直循环直到字符串结束。

我们可以使用指针来遍历字符串，实现过程是十分简单的


int my_atoi(char* arr)
{
	int n = 0;
	while (*arr != '\0')
	{
		n = n * 10 + *arr;
		arr++;
	}
}
2.空指针
我们总是避免不了传入空指针，我们这时候可以想到assert函数来断言一下，传入的到底是不是空指针。

3.前面有一大堆空格
我们可以通过循环跳过前面的空格

4.字符串长度为0
如果传入的字符串长度为0，那么指针解引用之后结果一定是'\0'，我们只要稍加注意就可以了。

5.整型溢出
我们要将字符串转化成整型，既然是整型，那么必然就会有范围，整型的最大值，最小值，在头文件limits.h中有定义，我们就可以直接调出最大值最小值。

我们要计算出的整型n就不可以定义为整型了，因为它是整形的话，那么它一定小于最大值，大于最小值。我们就必须将n定义为long long类型。

6.含有其它类型数据
我们只需要判断数组中第一个不是数字或者正负号的字符就可以了。
————————————————
版权声明：本文为CSDN博主「真的王」的原创文章，遵循CC 4.0 BY - SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https ://blog.csdn.net/m0_62179366/article/details/124066972
*/
//atoi    将一个字符串转化为一个整型
/*
#include<stdio.h>
#include<assert.h>
#include<limits.h>
#include<ctype.h>
enum state   //结构体成员：Value ErrValue
	
{
	Value,
	ErrValue
}statue;
enum state  statue = ErrValue;//先将statue的值给为错误❌

int my_atoi(const char* str)//const不可更改
{
	assert(str);//断言

	char* p = (char*)str;

	long long n = 0;//直接定义一个长整型，以免溢出
	int flag = 1;
	//字符串长度为0
	if (*str == '\0')//第一个字符就是终止符
	{
		return 0;
	}
	//字符串前面有很多空格
	while (*p == ' ')//遇到空格就跳过
	{
		p++;
	}
	//判断符号
	if (*p == '+')
	{
		flag = 1;
		p++;
	}
	else if (*p == '-')
	{
		flag = -1;
		p++;
	}
	//开始计算
	while (*p != '\0')
	{
		if (isdigit(*p))//判断字符串是否都为数字
		{
			n = n * 10 + flag * (*p -'0');//必须有-'0'，整合正负数（代表数字到0的距离），这样才可以保证为正，与符号位相乘
            //#include<ctype.h>
		
	//计算完毕
	if (*p == '\0')
	{
		statue = Value;//计算完毕成功后，改为真值
	}

	return (int)n;//强制转换为int类型
}/**
 特殊情况
 1前面有一大堆空格
 2传过来空指针
 3字符串长度为0
 4整形溢出
 5含有其它字符
 */
/*
int main()
{
	char arr[] = "12345678";
	int m = my_atoi(arr);
	if (statue == Value)//statue为改过后的真值，则输出
	{
		printf("%d\n", m);
	}
	if (statue == ErrValue)//如果为原来的错误值，则打印非法转化
	{
		printf("非法转化\n");
	}

	return 0;
}


*/


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>

enum State
{
	VALID,//0
	INVALID//1
};
enum State state = INVALID;//合法情况就一种，先判为非法，接下来判断较为方便
int my_atoi(const char* str)
{
	long long ret = 0;
	int flag = 1;
	assert(str);
	if (*str == '\0')//判断是否为空字符串
	{
		return 0;
	}
	while (isspace(*str))//跳过空白字符
	{
		str++;
	}
	if (*str == '+')//跳过正号
	{
		str++;
	}
	else if (*str == '-')//跳过负号
	{
		str++;
		flag = -1;
	}
	while (isdigit(*str))//开始转换数字字符直到非数字字符
	{
		ret = ret * 10 + (*str - '0') * flag;
		if ((ret > INT_MAX) || (ret < INT_MIN))//判断是否越界
		{
			return 0;
		}
		str++;
	}
	if (*str == '\0')//正常停止
	{
		state = VALID;
		return (int)ret;
	}
	else            //遇到非数字字符
	{
		state = VALID;
		return (int)ret;
	}
}
int main()
{
	char* p = "  -12345abc678";
	int ret = my_atoi(p);
	if (state == VALID)
	{
		printf("%d\n", ret);//-12345
	}
	return 0;
}




















